/*
申请内存：
当central cache向page cache申请内存时，page cache先检查对应位置有没有span，如果没有则向更大页寻找一个span，如果找到则分裂成两个。
比如：申请的是4页page，4页page后面没有挂span，则向后面寻找更大的span，假设在10页page位置找到一个span，则将10页page span分裂为一个4页pagespan和一个6页page span
如果找到_spanList[128]都没有合适的span，则向系统使用mmap、brk或者是VirtualAlloc等方式申请128页page span挂在自由链表中，再重复1中的过程。

需要注意的是central cache和page cache 的核心结构都是spanlist的哈希桶，但是他们是有本质区别的，central cache中哈希桶，是按跟thread cache一样的大小对齐关系映射的，
他的spanlist中挂的span中的内存都被按映射关系切好链接成小块内存的自由链表。而page cache 中的spanlist则是按下标桶号映射的，也就是说第i号桶中挂的span都是i页内存。




释放内存：

如果central cache释放回一个span，则依次寻找span的前后page id的没有在使用的空闲span，看是否可以合并，
如果合并继续向前寻找。这样就可以将切小的内存合并收缩成大的span，减少内存碎片
如果Central Cache中的span usecount=0说明切分给 thread cache的小块内存都回来了则Central Cache 把这个
span还给page cache,page cache通过页号查看前后相邻页是否空闲，是就合并出更大的页
*/


#ifndef CPAGECACHE_H
#define CPAGECACHE_H

#include <map>
#include "Common.h"
#include "ObjectPool.h"

#include <assert.h>
#include <iostream>


//页缓存  单例类
class PageCache
{
public:

	//返回单例类指针
	static PageCache* GetInstance() { return m_pageCache; }

	//获取对象到span的映射
	Span* MapObjectToSpan(void* obj);

	//获取一个k页的span
	Span* NewSpan(size_t k);

	//释放空闲span,合并相邻的span
	void ReleaseSpanToPageCache(Span* span);

	void testPrintSpanMap();

public:
	std::mutex m_pageMtx;
private:
	PageCache() {}
	PageCache(const PageCache&) = delete;

	SpanList				m_spanList[NPAGES];	
	ObjectPool<Span>		m_spanPool;
	std::map<size_t, Span*> m_idSpanMap; //size_t为页号，页号跟span的映射

	//单例
	static PageCache* m_pageCache;
};



#endif // CPAGECACHE_H
